/**
 * @description 小游戏类webpack单页配置文件
 * @author aodazhang 2020.12.03
 */
// 一.webpack插件
const { HotModuleReplacementPlugin } = require('webpack')
const { merge } = require('webpack-merge')
const htmlWebpackPlugin = require('html-webpack-plugin')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin') // 提取css
const TerserWebpackPlugin = require('terser-webpack-plugin') // 压缩js
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin') // 压缩css
const CompressionWebpackPlugin = require('compression-webpack-plugin') // html、css、js执行gizp
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer') // chunk包分析工具

// 二.webpack定义
const {
  entryFilePath,
  distFilePath,
  publicFilePath,
  entryName,
  templateName,
  templateTitle,
  templateDescription,
  jsFolderName,
  cssFolderName,
  imageFolderName,
  fontFolderName,
  mediaFolderName,
  hashRuleName,
  aliasName,
  isTypeScript,
  isCssModules,
  isProductionSourceMap,
  isProductionGzip,
  isProductionAnalyzer
} = require('./webpack.common')

// 三.webpack配置
let config = {
  performance: false,
  entry: {
    [entryName]: `${entryFilePath}/${entryName}.${isTypeScript ? 'ts' : 'js'}`
  },
  resolve: {
    // 路径别名：js -> '@/'、css -> '~@/'
    alias: aliasName,
    // 默认扩展名
    extensions: ['.ts', 'tsx', '.js', '.jsx']
  },
  plugins: [
    new CleanWebpackPlugin({
      cleanOnceBeforeBuildPatterns: [
        distFilePath // build前清空目录
      ]
    }),
    new htmlWebpackPlugin({
      template: `${publicFilePath}/${templateName}`, // html原始模板位置
      favicon: `${publicFilePath}/favicon.ico`, // html原始favicon位置
      filename: templateName, // html生成模板名
      chunks: [`${entryName}`], // 匹配entry的key
      title: templateTitle, // html标题
      meta: {
        viewport:
          'width=device-width,initial-scale=1.0,maximum-scale=1.0,minimum-scale=1.0,user-scalable=no,viewport-fit=cover', // html自适应移动端
        description: templateDescription // html描述
      }
    })
  ],
  module: {
    rules: [
      {
        test: /\.(js|jsx|ts|tsx)$/,
        exclude: /node_modules/,
        loader: 'babel-loader'
      },
      {
        test: /\.(jpg|jpeg|png|gif|bmp|svg)$/,
        use: {
          loader: 'url-loader',
          options: {
            name: `${hashRuleName}.[ext]`,
            outputPath: `${imageFolderName}/`,
            limit: 10 * 1024 // 10kb以下base64、10kb以上url
          }
        }
      },
      {
        test: /\.(eot|ttf|woff|woff2)$/,
        use: {
          loader: 'file-loader',
          options: {
            name: `${hashRuleName}.[ext]`,
            outputPath: `${fontFolderName}/` // 全部url
          }
        }
      },
      {
        test: /\.(mp3)$/,
        use: {
          loader: 'file-loader',
          options: {
            name: `${hashRuleName}.[ext]`,
            outputPath: `${mediaFolderName}/` // 全部url
          }
        }
      }
    ]
  },
  optimization: {
    usedExports: true, // 开启tree shaking
    splitChunks: {
      chunks: 'all', // 对同步+异步引入的js开启code splitting
      cacheGroups: {
        // vendors组规则：node_modules中文件使用
        vendor: {
          test: /node_modules/,
          name: 'node_modules',
          priority: 1, // 拆分权重：优先级1
          minSize: 0 * 1024, // 拆分最小体积：进行拆分js文件的最小体积，>0kb拆分
          minChunks: 1 // 拆分最小复用：进行拆分js文件的最少import次数，>1次拆分
        },
        // common组规则
        common: {
          name: 'common',
          priority: 0, // 优先级0
          minSize: 0 * 1024, // >0kb拆分
          minChunks: 2 // >1次拆分
        }
      }
    }
  }
}

// 开发环境
if (process.env.NODE_ENV === 'development') {
  const developmentConfig = {
    mode: 'development',
    devtool: 'cheap-module-eval-source-map',
    output: {
      publicPath: '/',
      filename: '[name].js',
      path: distFilePath
    },
    devServer: {
      contentBase: distFilePath,
      port: 3000,
      open: false, // 禁止自动打开浏览器
      hot: true, // webpack-dev-server开启热模块重载功能hmr
      hotOnly: true // hmr不生效浏览器也不刷新
    },
    plugins: [new HotModuleReplacementPlugin()],
    module: {
      rules: [
        {
          test: /\.(css|less)$/,
          use: [
            'style-loader',
            {
              loader: 'css-loader',
              options: {
                importLoaders: 2, // css中通过import引入的文件，也要先执行less-loade + postcss-loader
                modules: isCssModules // css模块化
              }
            },
            'postcss-loader',
            'less-loader'
          ]
        }
      ]
    }
  }
  config = merge(config, developmentConfig)
}

// 生产环境
if (process.env.NODE_ENV === 'production') {
  const productionConfig = {
    mode: 'production',
    devtool: isProductionSourceMap ? 'cheap-module-source-map' : 'none',
    output: {
      publicPath: './',
      filename: `${jsFolderName}/${hashRuleName}.js`,
      path: distFilePath
    },
    plugins: [
      new MiniCssExtractPlugin({
        filename: `${cssFolderName}/${hashRuleName}.css`,
        chunkFilename: `${cssFolderName}/${hashRuleName}.chunk.css`
      })
    ],
    module: {
      rules: [
        {
          test: /\.(css|less)$/,
          use: [
            MiniCssExtractPlugin.loader,
            {
              loader: 'css-loader',
              options: {
                importLoaders: 2, // css中通过import引入的文件，也要先执行less-loade + postcss-loader
                modules: isCssModules // css模块化
              }
            },
            'postcss-loader',
            'less-loader'
          ]
        }
      ]
    },
    optimization: {
      minimize: false
    }
  }

  !isProductionSourceMap &&
    (productionConfig.optimization = {
      minimize: true, // 开启压缩
      minimizer: [
        new TerserWebpackPlugin(), // 压缩js
        new OptimizeCssAssetsWebpackPlugin() // 压缩css
      ]
    })

  isProductionGzip &&
    (productionConfig.plugins = [
      ...productionConfig.plugins,
      new CompressionWebpackPlugin({
        test: /\.(html|css|js)$/, // 匹配文件类型
        algorithm: 'gzip', // 压缩算法
        threshold: 0 * 1024, // gzip压缩大小阈值(kb)：文件大小>0kb执行压缩
        minRatio: 0.8, // gzip压缩比率阈值(%)：文件压缩阈值<0.8执行压缩
        deleteOriginalAssets: false, // 不删除原始文件
        filename: '[path][base].gz' // gizp生成文件名
      })
    ])

  isProductionAnalyzer &&
    (productionConfig.plugins = [
      ...productionConfig.plugins,
      new BundleAnalyzerPlugin({
        openAnalyzer: false, // 是否启动本地服务
        analyzerPort: 3001, // 本地服务端口号：http://localhost:3001
        analyzerMode: 'static', // 只输出静态html文件
        reportFilename: 'analyzer.html', // 分析文件名称
        reportTitle: `${templateTitle}性能分析结果` //
      })
    ])

  config = merge(config, productionConfig)
}

module.exports = config
